package cn.rayfoo.common.interceptor;

import cn.rayfoo.common.exception.MyException;
import cn.rayfoo.common.response.HttpStatus;
import cn.rayfoo.common.util.net.ClientUtil;
import cn.rayfoo.common.util.redis.RedisUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author rayfoo@qq.com
 * @version 1.0
 * @date 2020/8/6 11:49
 * 登录次数校验拦截器
 */
@NoArgsConstructor
@Getter
@Slf4j
public class AccessInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 需要拦截的URL
     */
    private String interceptorUrl;

    /**
     * 规定的时间范围 单位：秒
     */
    private Long timeBound;

    /**
     * 规定时间内允许的的访问量阈值
     */
    private Integer requestNum;


    /**
     * @param interceptorUrl 要拦截的URL
     * @param timeBound      规定的时间范围
     * @param requestNum     时间范围内的请求次数超过多少时禁止访问
     */
    public AccessInterceptor(String interceptorUrl, Long timeBound, Integer requestNum) {
        this.interceptorUrl = interceptorUrl;
        this.timeBound = timeBound;
        this.requestNum = requestNum;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断该ip地址五分钟内注册了多少次 如果超过五次，将其ip列入黑名单十分钟。 每注册一次给此id加1
        String ipAddr = ClientUtil.getIpAddr(request) + interceptorUrl;
        //判断ip地址是否存在
        if (redisUtil.hasKey(ipAddr)) {
            //获取五分钟内获取验证码的次数
            Integer count = (Integer) redisUtil.get(ipAddr);
            //如果在x分钟内获取了超过x次
            if (count > requestNum) {
                //获取过期时间
                long expire = redisUtil.getExpire(ipAddr);
                log.error(ClientUtil.getIpAddr(request) + "对" + interceptorUrl + "操作频繁，此接口已将其暂时列入黑名单");
                //告知用户限制时间还有多久
                throw MyException.builder().code(HttpStatus.INTERNAL_SERVER_ERROR.value()).msg("您的操作过于频繁，请" + expire + "秒后重试！").build();
            }
            //不到五次就累加
            redisUtil.incr(ipAddr, 1L);
        } else {
            //不存在的话 创建
            redisUtil.set(ipAddr, 1L);
            //过期时间设置为time秒
            redisUtil.expire(ipAddr, timeBound);
        }

        return true;
    }
}
